package com.mingserve.beetech;

import com.alibaba.fastjson2.JSON;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.util.Comparator;
import java.util.List;

/**
 * 必创传感器解析
 *         字段	数据类型	    说明
 *         1	uint32_t	采集时间（时间戳）¹
 *         2	uint16_t	波形格式类型 ²
 *         3	uint16_t	通道数（X/Y/Z） ³
 *         4	uint16_t	通道1（X轴）单位 ⁴
 *         5	uint16_t	通道2（Y轴）单位 ⁴
 *         6	uint16_t	通道3（Z轴）单位 ⁴
 *         7	uint16_t	通道1（X轴）采样率（KHz）
 *         8	uint16_t	通道2（Y轴）采样率（KHz）
 *         9	uint16_t	通道3（Z轴）采样率（KHz）
 *         10	uint16_t	通道1（X轴）截止频率 ⁵
 *         11	uint16_t	通道2（Y轴）截止频率 ⁵
 *         12	uint16_t	通道3（Z轴）截止频率 ⁵
 *         13	uint32_t	通道1（X轴）数据长度（字节）
 *         14	uint32_t	通道2（Y轴）数据长度（字节）
 *         15	uint32_t	通道3（Z轴）数据长度（字节）
 *         16	uint32_t	通道1（X轴）数据起始地址（字节）⁶
 *         17	uint32_t	通道2（Y轴）数据起始地址（字节）⁶
 *         18	uint32_t	通道3（Z轴）数据起始地址（字节）⁶
 *         19	int16_t	温度值（需除以100）
 *         注意：
 *         1. Unix 时间戳是从 1970 年 1 月 1 日（UTC/GMT 的午夜）开始所经过的秒数，不考虑闰秒。
 *         2. VA330 波形格式类型为 6；
 *         3. Bit0~Bit15 依此对应通道 1~16；
 *         4. 固定值为 7，即：（m/s² ）；
 *         5. 取值为 0~6，分别对应 20KHz、10KHz、5KHz、2KHz、1.5KHz、1KHz、500Hz
 *         6. VA330 的加速度值和温度值数据类型为 int16_t，X 轴（Channel 1）、Y 轴（Channel 2）和 温度值（Channel 4）需除以 100 得到真实值，Z（Channel 3）轴需除以 30 得到真实值；
 *
 * @author lvwshuai
 * @date 2024-05-21 13:09
 */
@Component
public class BeeTechUtils
{
    public static void main(String[] args) throws IOException {

        File file = ResourceUtils.getFile("classpath:data.json");
        String jsonContent = Files.readString(file.toPath());
        List<BeeTechWaveModel> waveList = JSON.parseArray(jsonContent, BeeTechWaveModel.class)
                .stream()
                .filter(b -> b.getCmd() == 2)
                .sorted(Comparator.comparing(BeeTechWaveModel::getPos))
                .toList();

        StringBuilder sb = new StringBuilder();
        for (BeeTechWaveModel wave : waveList) {
            sb.append(wave.getData());
        }
        parseVA330Data(sb.toString());
    }

    /**
     * 解析VA330数据
     *
     * @param hexData 十六进制数据
     */
    public static void parseVA330Data(String hexData)
    {
        // 转换为byte[]
        byte[] binaryData = hexStringToByteArray(hexData);

        // 解析头部信息，小端序
        ByteBuffer buffer = ByteBuffer.wrap(binaryData).order(ByteOrder.LITTLE_ENDIAN);

        // 1. 解析元数据
        long timestamp = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        int waveformType = buffer.getShort() & 0xFFFF;  // uint16_t
        int channelCount = buffer.getShort() & 0xFFFF;  // uint16_t
        int xUnit = buffer.getShort() & 0xFFFF;        // uint16_t
        int yUnit = buffer.getShort() & 0xFFFF;        // uint16_t
        int zUnit = buffer.getShort() & 0xFFFF;        // uint16_t
        int xSampleRate = buffer.getShort() & 0xFFFF;  // uint16_t (KHz)
        int ySampleRate = buffer.getShort() & 0xFFFF;  // uint16_t (KHz)
        int zSampleRate = buffer.getShort() & 0xFFFF;  // uint16_t (KHz)
        int xCutoffFreq = buffer.getShort() & 0xFFFF;  // uint16_t
        int yCutoffFreq = buffer.getShort() & 0xFFFF;  // uint16_t
        int zCutoffFreq = buffer.getShort() & 0xFFFF;  // uint16_t
        long xDataLength = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        long yDataLength = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        long zDataLength = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        long xDataOffset = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        long yDataOffset = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        long zDataOffset = buffer.getInt() & 0xFFFFFFFFL; // uint32_t
        float temperature = buffer.getShort() / 100.0f;    // int16_t (需除以100)

        // 2. 解析X/Y/Z数据 int16_t数组
        short[] xData = readChannelData(binaryData, (int) xDataOffset, (int) xDataLength);
        short[] yData = readChannelData(binaryData, (int) yDataOffset, (int) yDataLength);
        short[] zData = readChannelData(binaryData, (int) zDataOffset, (int) zDataLength);

        // 3. 转换为实际物理值
        float[] xValues = new float[xData.length];
        float[] yValues = new float[yData.length];
        float[] zValues = new float[zData.length];

        for (int i = 0; i < xData.length; i++) {
            xValues[i] = xData[i] / 100.0f;  // X 轴 ÷100
            yValues[i] = yData[i] / 100.0f;  // Y 轴 ÷100
            zValues[i] = zData[i] / 30.0f;   // Z 轴 ÷30
        }

        // 4. 打印元数据
        System.out.println("=== 传感器数据头部 ===");
        System.out.printf("采集时间: %d%n", timestamp);
        System.out.printf("波形格式: %d%n", waveformType);
        System.out.printf("通道数: %d%n", channelCount);
        System.out.printf("X轴单位: %d%n", xUnit);
        System.out.printf("Y轴单位: %d%n", yUnit);
        System.out.printf("Z轴单位: %d%n", zUnit);
        System.out.printf("X轴采样率: %d KHz%n", xSampleRate);
        System.out.printf("Y轴采样率: %d KHz%n", ySampleRate);
        System.out.printf("Z轴采样率: %d KHz%n", zSampleRate);
        System.out.printf("X轴截止频率: %d%n", xCutoffFreq);
        System.out.printf("Y轴截止频率: %d%n", yCutoffFreq);
        System.out.printf("Z轴截止频率: %d%n", zCutoffFreq);
        System.out.printf("X轴数据长度: %d 字节%n", xDataLength);
        System.out.printf("Y轴数据长度: %d 字节%n", yDataLength);
        System.out.printf("Z轴数据长度: %d 字节%n", zDataLength);
        System.out.printf("X轴数据地址: %d%n", xDataOffset);
        System.out.printf("Y轴数据地址: %d%n", yDataOffset);
        System.out.printf("Z轴数据地址: %d%n", zDataOffset);
        System.out.printf("温度: %.2f °C%n", temperature);

        System.out.printf("X轴加速度，长度 %d: %s%n", xData.length, JSON.toJSONString(xValues));
        System.out.printf("y轴加速度，长度 %d: %s%n", yData.length, JSON.toJSONString(yValues));
        System.out.printf("z轴加速度，长度 %d: %s%n", zData.length, JSON.toJSONString(zValues));
    }

    /**
     * 将16进制字符串转换为字节数组
     *
     * @param hexString 16进制字符串
     * @return 字节数组
     */
    private static byte[] hexStringToByteArray(String hexString)
    {
        // 移除所有非16进制字符（如空格、换行）
        hexString = hexString.replaceAll("[^0-9A-Fa-f]", "");
        int len = hexString.length();

        // 检查长度是否为偶数
        if (len % 2 != 0) {
            throw new IllegalArgumentException("十六进制字符串长度必须为偶数");
        }
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
//        for (int i = 0; i < bytes.length; i++) {
//            int index = i * 2;
//            String hex = hexString.substring(index, index + 2);
//            bytes[i] = (byte) Integer.parseInt(hex, 16);
//        }
        return bytes;
    }

    /**
     * 读取指定通道的数据
     *
     * @param data      数据缓冲区
     * @param offset    数据偏移量
     * @param length    数据长度
     * @return 指定通道的数据
     */
    private static short[] readChannelData(byte[] data, int offset, int length)
    {
        if(offset + length > data.length) {
            throw new IllegalArgumentException("数据超出缓冲区范围");
        }

        short[] result = new short[length / 2];
        ByteBuffer.wrap(data, offset, length)
                .order(ByteOrder.LITTLE_ENDIAN)
                .asShortBuffer()
                .get(result);
        return result;

//        ByteBuffer buffer = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
//        int dataCountX = (int) (length / 2); // 每个int16_t为2字节
//        short[] result = new short[dataCountX];
//        buffer.position((int) offset); // 定位到X轴数据开始
//        for (int i = 0; i < dataCountX; i++) {
//            result[i] = buffer.getShort();
//        }
    }
}